using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace EuropeEngulfed.NET
{
    class FleetTransferMove : Move
    {
        MapInfo.RegionID seaRegionIDFrom;
        MapInfo.RegionID seaRegionIDTo;
        MapInfo.CountryID countryOfFleet;

        public FleetTransferMove(GameTurn.GameDate gameDate, GameTurn.GamePhase gamePhase, GameTurn.GameSubPhase subPhase, MapInfo.RegionID seaRegionIDFrom, MapInfo.RegionID seaRegionIDTo, MapInfo.CountryID countryOfFleet)
            : base(gameDate, gamePhase, subPhase)
        {
            this.seaRegionIDFrom = seaRegionIDFrom;
            this.seaRegionIDTo = seaRegionIDTo;
            this.countryOfFleet = countryOfFleet;
        }

        public MapInfo.RegionID SeaRegionIDFrom
        {
            get
            {
                return seaRegionIDFrom;
            }
        }

        public MapInfo.RegionID SeaRegionIDTo
        {
            get
            {
                return seaRegionIDTo;
            }
        }

        public MapInfo.CountryID CountryOfFleet
        {
            get
            {
                return this.countryOfFleet;
            }
        }

        protected override void ProcessMove(GameState gameState)
        {
            SeaRegionState seaRegionStateFrom = (SeaRegionState)gameState.GetRegionState(this.seaRegionIDFrom);
            SeaRegionState seaRegionStateTo = (SeaRegionState)gameState.GetRegionState(this.seaRegionIDTo);

            for(int i = 0; seaRegionStateFrom.GetFleetPointAt(i) != null; i++)
            {
                FleetPoint fleetPointToRemove = seaRegionStateFrom.GetFleetPointAt(i);
                if(!fleetPointToRemove.WithoutTransport)
                {
                    if(fleetPointToRemove.CountryOwner == this.countryOfFleet)
                    {
                        seaRegionStateFrom.RemoveFleetPoint(fleetPointToRemove);
                        break;
                    }
                }
            }

            MapInfo.CountryID countryOfNewFleet = this.countryOfFleet;
            if(this.seaRegionIDFrom == MapInfo.RegionID.MediteraneanSea && this.countryOfFleet == MapInfo.CountryID.Italy)
                countryOfNewFleet = MapInfo.CountryID.Germany;
            else if(this.seaRegionIDFrom == MapInfo.RegionID.AtlanticOcean && this.seaRegionIDTo == MapInfo.RegionID.MediteraneanSea && this.countryOfFleet == MapInfo.CountryID.Germany)
                countryOfNewFleet = MapInfo.CountryID.Italy;
            FleetPoint fleetPointToAdd = new FleetPoint(countryOfNewFleet);
            fleetPointToAdd.WithoutTransport = true;
            seaRegionStateTo.AddFleetPoint(fleetPointToAdd);
        }

        private bool AxisPlayerCanTranferFleetPoints(IGameStateInfoProvider gameStateInfoProvider, MapInfo.RegionID from, MapInfo.RegionID to)
        {//8.32 AXIS FLEET POINT TRANSFER
            if ((from == MapInfo.RegionID.BalticSea && to == MapInfo.RegionID.AtlanticOcean)
            || (from == MapInfo.RegionID.AtlanticOcean && to == MapInfo.RegionID.BalticSea))
            {//8.321 Axis transfer between the Baltic and Atlantic
                if (gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Rhur)) || gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Denmark)))
                    return true;
            }
            else if ((from == MapInfo.RegionID.AtlanticOcean && to == MapInfo.RegionID.MediteraneanSea)
                || (from == MapInfo.RegionID.MediteraneanSea && to == MapInfo.RegionID.AtlanticOcean))
            {//8.322 Axis transfer from the Atlantic to the Mediterranean
                if (!(gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Gibraltar)) && gameStateInfoProvider.IsNationAtWar(MapInfo.CountryID.Italy)))
                    return false;
                if (from == MapInfo.RegionID.MediteraneanSea && to == MapInfo.RegionID.AtlanticOcean)
                {
                    if (!(gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Alexandria)) && gameStateInfoProvider.IsNationAtWar(MapInfo.CountryID.USSR)))
                        return false;
                }
                return true;
            }
            return false;
        }

        public override bool IsLegal(IGameStateInfoProvider gameStateInfoProvider, ref string ruleString)
        {
            //TODO Add check here for in supply port (as opposed to just controlled)
            if(this.CountryOfFleet == MapInfo.CountryID.France || this.CountryOfFleet == MapInfo.CountryID.GreatBritain || this.CountryOfFleet == MapInfo.CountryID.Italy || this.CountryOfFleet == MapInfo.CountryID.Germany)
            {
                ruleString = "Sea regions are not adjacent";
                switch(this.seaRegionIDTo)
                {
                    case MapInfo.RegionID.BalticSea:
                        if (this.seaRegionIDFrom != MapInfo.RegionID.AtlanticOcean)
                            return false;
                        break;
                    case MapInfo.RegionID.AtlanticOcean:
                        if (this.seaRegionIDFrom != MapInfo.RegionID.BalticSea && this.seaRegionIDFrom != MapInfo.RegionID.MediteraneanSea)
                            return false;
                        break;
                    case MapInfo.RegionID.MediteraneanSea:
                        if (this.seaRegionIDFrom != MapInfo.RegionID.AtlanticOcean)
                            return false;
                        break;
                    default:
                        return false;
                }

                if (seaRegionIDTo == MapInfo.RegionID.BalticSea && this.countryOfFleet != MapInfo.CountryID.Germany)
                {
                    ruleString = "Cannot move a non-German fleet to the Baltic";
                    return false;
                }

                bool AxisFleetMove = false;
                if (countryOfFleet == MapInfo.CountryID.Germany || countryOfFleet == MapInfo.CountryID.Italy)
                {
                    if (!AxisPlayerCanTranferFleetPoints(gameStateInfoProvider, this.seaRegionIDFrom, this.seaRegionIDTo))
                    {
                        ruleString = "Invalid Axis Fleet Point Transfer see 8.32 AXIS FLEET POINT TRANSFER";
                        return false;
                    }
                    AxisFleetMove = true;
                }

                bool foundAControlledPort = false;
                foreach (Edge<Region, Adjacency> edge in MapInfo.GetEdgesFromRegion(this.seaRegionIDTo))
                {
                    MapInfo.RegionID otherRegion;
                    if (edge.Start.RegionID != seaRegionIDTo)
                        otherRegion = edge.Start.RegionID;
                    else
                        otherRegion = edge.End.RegionID;
                    if(MapInfo.IsLandRegion(otherRegion))
                    {
                        SeaLandAdjacency seaLandConnection = (SeaLandAdjacency)edge.Data;
                        if(seaLandConnection.Port)
                        {
                            if(AxisFleetMove)
                            {
                                if(gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(otherRegion)))
                                {
                                    foundAControlledPort = true;
                                    break;
                                }
                            }
                            else
                            {
                                if(gameStateInfoProvider.IsAlliedCountry(gameStateInfoProvider.GetRegionControl(otherRegion)))
                                {
                                    foundAControlledPort = true;
                                    break;
                                }
                            }
                        }
                    }
                }

                if(!foundAControlledPort)
                {
                    ruleString = "8.3 Fleet Point Transfers... a supplied friendly controlled port must be in the intended Sea-zone";
                    return false;
                }

                int numFleetTransfersAlreadyTaken = gameStateInfoProvider.GetNumFleetTransfersMadeThisTurn(this.CountryOfFleet);
                if(this.CountryOfFleet == MapInfo.CountryID.Germany || this.CountryOfFleet == MapInfo.CountryID.Italy)
                {
                    if (numFleetTransfersAlreadyTaken > 0)
                    {
                        ruleString = "8.32 AXIS FLEET POINT TRANSFER: The Axis player may transfer ONE Fleet Point per turn";
                        return false;
                    }
                }
                else
                {
                    if (gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Gibraltar)))
                    {
                        if(gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Alexandria))
                            || gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Sinai)))
                        {
                            ruleString = "8.31 WESTERN ALLIED FLEET POINT TRANSFER:... the Axis control Gibraltar, then only one Fleet Point per turn may be transferred, and only if the Western Allies control both the Alexandria and Sinai Desert areas.";
                            return false;
                        }
                    }

                    if(numFleetTransfersAlreadyTaken > 1)
                    {
                        ruleString = "8.31 WESTERN ALLIED FLEET POINT TRANSFER:...Britain and France may transfer two points each per turn";
                        return false;
                    }
                    else if(numFleetTransfersAlreadyTaken > 0 && gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(MapInfo.RegionID.Gibraltar)))
                    {
                        ruleString = "8.31 WESTERN ALLIED FLEET POINT TRANSFER:...If the Axis control Gibraltar, then only one Fleet Point per turn may be transferred";
                        return false;
                    }
                }

                return true;
            }
            else
            {
                ruleString = "Invalid fleet to move";
                return false;
            }
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("Move");
            System.Xml.XmlAttribute typeAttr = xml.CreateAttribute("Type");
            System.Xml.XmlAttribute seaRegionIDFromAttr = xml.CreateAttribute("seaRegionIDFrom");
            System.Xml.XmlAttribute seaRegionIDToAttr = xml.CreateAttribute("seaRegionIDTo");
            System.Xml.XmlAttribute countryOfFleetAttr = xml.CreateAttribute("countryOfFleet");

            nodeToReturn.AppendChild(gameTurn.Serialise(xml));
            typeAttr.Value = this.GetType().ToString();
            seaRegionIDFromAttr.Value = Enum.GetName(seaRegionIDFrom.GetType(), seaRegionIDFrom);
            seaRegionIDToAttr.Value = Enum.GetName(seaRegionIDTo.GetType(), seaRegionIDTo);
            countryOfFleetAttr.Value = Enum.GetName(countryOfFleet.GetType(), countryOfFleet);

            nodeToReturn.Attributes.Append(typeAttr);
            nodeToReturn.Attributes.Append(seaRegionIDFromAttr);
            nodeToReturn.Attributes.Append(seaRegionIDToAttr);
            nodeToReturn.Attributes.Append(countryOfFleetAttr);

            return nodeToReturn;
        }

        public new static Move Deserialise(System.Xml.XmlNode node)
        {
            if (node.Attributes["Type"].Value == typeof(FleetTransferMove).ToString() && node.Name == "Move")
            {
                GameTurn parsedGameTurn = GameTurn.Deserialise(node.SelectSingleNode("GameTurn"));
                return new FleetTransferMove(parsedGameTurn.CurrentGameDate, parsedGameTurn.CurrentGamePhase, parsedGameTurn.CurrentGameSubPhase, (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["seaRegionIDFrom"].Value), (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["seaRegionIDTo"].Value), (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["countryOfFleet"].Value));
            }
            else
                throw new InvalidOperationException();
        }

        public override System.Windows.Forms.TreeNode GetMoveTreeNode(System.Windows.Forms.TreeView treeView)
        {
            System.Windows.Forms.TreeNode treeNode = new System.Windows.Forms.TreeNode(Enum.GetName(this.countryOfFleet.GetType(), this.countryOfFleet) + " Fleet Transfer from " + MapInfo.GetRegionName(this.seaRegionIDFrom) + " to " + MapInfo.GetRegionName(this.seaRegionIDTo));
            FleetPoint fleet = new FleetPoint(this.countryOfFleet);
            if (!treeView.ImageList.Images.ContainsKey(fleet.GetTreeViewImageListKey(true)))
            {
                Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                Graphics g = Graphics.FromImage(b);
                PlayingPieceGraphics.PaintFleetPointFace(g, fleet, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height));
                treeView.ImageList.Images.Add(fleet.GetTreeViewImageListKey(true), b);
            }
            treeNode.ImageIndex = treeView.ImageList.Images.IndexOfKey(fleet.GetTreeViewImageListKey(true));
            treeNode.SelectedImageIndex = treeNode.ImageIndex;

            return treeNode;
        }

        public override string GetStringForNetworkMessage()
        {
            return MapInfo.GetCountryAdjective(this.countryOfFleet) + " Fleet transfered from " + Enum.GetName(typeof(MapInfo.RegionID), this.seaRegionIDFrom) + " to " + Enum.GetName(typeof(MapInfo.RegionID), this.seaRegionIDTo);
        }
    }
}
